package scenic;

import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.util.Observable;

import scenic.jni.Renderer;

/**
 * The Image class represents an image. Image objects are used
 * to display images. The image data is stored in video memory. 
 * 
 * The format of the image data is specified by the format 
 * attribute. Different formats are defined in the Format
 * class.
 */
public class Image extends Observable {
	private int id;
	private int width;
	private int height;
	private int format;

	/** Constructs an empty image
	 */
	public Image() {
		create(0, 0, 0);
	}
	
	/**
	 * Constructs an image with given parameters. 
	 * 
	 * @param width the width of the image.
	 * @param height the height of the image.
	 * @param format the format of the image (must be one of the 
	 * constants defined in the Format class).
	 */
	public Image(int width, int height, int format) {
		create(width, height, format);
	}
	
	/**
	 * Creates an image from the given BufferedImage.
	 * 
	 * @param image the source image.
	 */
	public Image(BufferedImage image) {
		DataBuffer db = image.getRaster().getDataBuffer();
		DataBufferByte dfb = (DataBufferByte)db;		

		create(image.getWidth(), image.getHeight(), Format.R8G8B8);		
		write(dfb.getData());
	}
	
	protected void finalize() {
		free();
	}
	
	/**
	 * Gets the width of the image.
	 */
	public int getWidth() {
		return width;
	}

	/**
	 * Gets the height of the image.
	 */
	public int getHeight() {
		return height;
	}
	
	/**
	 * Gets the format of the image. The format is one of the constants
	 * defined in the Format class.
	 */
	public int getFormat() {
		return format;
	}
	
	/**
	 * Creates an image with the given parameters. The new image replaces
	 * the old image. Pixel data is not copied to the new image.
	 * 
	 * @param width the width of the image.
	 * @param height the height of the image.
	 * @param format the format of the image (must be one of the 
	 * constants defined in the Format class).
	 */
	public void create(int width, int height, int format) {
		free();
		this.width = width;
		this.height = height;
		this.format = format;
		createNativeImage();
		markChanged();
	}
	
	public void markChanged() {
		setChanged();
		notifyObservers();
		clearChanged();		
	}
	
	private boolean createNativeImage() {
		Renderer renderer = new Renderer();
		
		id = renderer.createImage(width, height, format);
		return true;
	}
	
	public int getId() {
		return id;
	}
	
	/**
	 * Frees the resources associated with the image.
	 */
	public void free() {
		this.width = 0;
		this.height = 0;
		this.format = 0;
		
		if(id != 0) {
			Renderer renderer = new Renderer();

			renderer.deleteImage(id);
			id = 0;
		}	
		markChanged();
	}
	
	/**
	 * Writes the entire pixel data of the image.
	 * 
	 * @param data the pixel data (must be in the same format as the image).
	 */
	public void write(byte[] data) {
		write(0, 0, width, height, data);
	}


	/**
 	 * Writes the pixel data of the image in the given rectangle.
 	 * 
	 * @param x the left side of the rectangle.
	 * @param y the top of the rectangle.
	 * @param width the width of the rectangle.
	 * @param height the height of the rectangle.
	 * @param data the pixel data (must be in the same format as the image).
	 */
	public void write(int x, int y, int width, int height, byte[] data) {
		Renderer renderer = new Renderer();

		renderer.writeImage(id, x, y, width, height, data, 0, width);
		markChanged();
	}
}
